﻿/*------------------------------------------------------------------------

TEXTURE2DRD.HPP v1.0.3

Copyright 楊志賢 CxxlMan, 2014 - 2015
All Rights Reserved

------------------------------------------------------------------------*/

#if !defined(__TEXTURE2DRD_HPP_Cxxl3D)
#define __TEXTURE2DRD_HPP_Cxxl3D

#include <Sys\VERTEXFMT.HPP>
#include <Sys\RENDERUNIT.HPP>
#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
#include <Sys\CSMART_PTR.HPP>
#include <Sys\CSMART_ARRAY.HPP>
#include <Sys\RenderUnit\SysRenderDatagram\TEXTURERD.HPP>

namespace Cxxl3D
{


// 傳遞給 ITextureRD_2D 用的資料結構
class dataTexture_2D
{
  CxxlMan::CriticalSec csObject;

  C3D_UINT m_Width, m_Height;
  CxxlMan::CSmart_Array<const tagPIXEL> m_Texture_Array;
public:

  void cxxlFASTCALL LockTexture() const
  {
    csObject.Enter();
  }

  void cxxlFASTCALL UnLockTexture() const
  {
    csObject.Leave();
  }

  // Constructor
  dataTexture_2D()
    :m_Texture_Array(NULL)
  {
    m_Width = m_Height = 0;
  }

  // Copy Constructor
  dataTexture_2D(const dataTexture_2D &Src)
    :m_Texture_Array(NULL)
  {
    Src.LockTexture();
    m_Width = Src.m_Width;
    m_Height = Src.m_Height;

    m_Texture_Array = Src.m_Texture_Array;
    Src.UnLockTexture();
  }

  // Destructor
  ~dataTexture_2D()
  {
  }

  // Assign
  dataTexture_2D & operator=(const dataTexture_2D &Src)
  {
    Src.LockTexture();

    C3D_UINT tmpWidth = Src.m_Width;
    C3D_UINT tmpHeight = Src.m_Height;

    CxxlMan::CSmart_Array<const tagPIXEL> tmpTexture_Array = Src.m_Texture_Array;  

    Src.UnLockTexture();

    this->LockTexture();

    m_Width =  tmpWidth;
    m_Height = tmpHeight;

    m_Texture_Array = tmpTexture_Array;

    this->UnLockTexture();

    return *this;
  }

  void cxxlFASTCALL SetData(const C3D_UINT Width, const C3D_UINT Height, const CxxlMan::CSmart_Array<const tagPIXEL> &Texture_Array)
  {
    this->LockTexture();

    m_Width = Width;
    m_Height = Height;

    m_Texture_Array = Texture_Array;

    this->UnLockTexture();
  }

  void cxxlFASTCALL GetData(C3D_UINT &Width, C3D_UINT &Height, CxxlMan::CSmart_Array<const tagPIXEL> &Texture_Array) const
  {
    this->LockTexture();

    Width = m_Width;
    Height = m_Height;

    Texture_Array = m_Texture_Array;

    this->UnLockTexture();
  }

};

class ITextureRD_2D;

// 供 Render 單元要求 ITextureRD_2D 重新取得 Texture 資料時，藉由此介面取得
class IRetrieveTexture2D:virtual public CxxlMan::cxxlPreserve2
{


protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && CxxlMan::cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IRetrieveTexture2D()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IRetrieveTexture2D()
  {
  }

public:

  // 須實作
  virtual void cxxlFASTCALL GetTexture(const CxxlMan::Smart_Ptr< ITextureRD_2D > &) = 0;
};

// Render 單元要叫用 ITextureRD 提供給其叫用的功能，須繼承此介面
class ITextureBridge;

// 以 Mipmap 作為貼圖紋理
class ITextureRD_2D:public ITextureRD, public DepositStore
{
  virtual void cxxlFASTCALL SysInit(const CxxlMan::UNICODE_String &TextureID) = 0;

  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return ITextureRD_2D_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

  // 供 Render 單元取得 Mipmap
  virtual bool cxxlFASTCALL GetMipmap(const unsigned char ***Mipmaps, const unsigned int **WidthHeight, unsigned int *LevelNum) const = 0;

  // 供 Render 單元取得屬性資料
  virtual void cxxlFASTCALL GetAttr(unsigned char &TextureAddrMode, unsigned int &TextureClampBorderRGBA, unsigned char &TextureMipmapMode, unsigned char &BlendMode, CxxlMan::CSmart_Ptr<const C3DMatrix4x4> &TextureMatrix_Arg, char &AutoTexCoordIndexMode) const = 0;

protected:


  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && CxxlMan::cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  ITextureRD_2D()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ITextureRD_2D_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~ITextureRD_2D()
  {
  }

public:

  // 取得貼圖資料識別，IRetrieveTexture 的實作須有能力藉此將正確的頂點資料由 MipmapMake() 置入
  virtual CxxlMan::UNICODE_String cxxlFASTCALL GetVertexID() = 0;

  // 使用 dataTexture_2D 建立 Mipmap
  virtual void cxxlFASTCALL MipmapMake(const CxxlMan::CSmart_Ptr<const dataTexture_2D> &Texture_Arg) = 0;

  // 通知其儲存的 Mipmap 所依據的 dataTexture_2D 資料已被修改，只有 Crushable() 設定過才能再去取得，否則仍使用儲存的 Mipmap。
  // 若未使用 Crushable()，不如再用 MipmapMake() 更新資料
  virtual void cxxlFASTCALL Modified() = 0;

  // 指示當 Render 單元取出 Mipmap 資料後，可以將之清除，內定是不清除的。
  // 須提供一個 IRetrieveTexture2D，作為須取出 Mipmap 資料時的處理方法
  // IRetrieveTexture2D_Arg 不可為 NULL，否則 Crushable() 呼叫無效
  virtual void cxxlFASTCALL Crushable(const CxxlMan::Smart_Ptr<IRetrieveTexture2D> &IRetrieveTexture2D_Arg) = 0;

  // 建立 ITextureRD_2D 物件，失敗傳回 NULL
  // TextureID = 貼圖資料識別
  static CxxlMan::Smart_Ptr<ITextureRD_2D> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &TextureID)
  {
    CxxlMan::Smart_Ptr<ITextureRD_2D> r = CxxlMan::Preserve2_Cast<ITextureRD_2D>( CxxlMan::cxxlCM_GetElement(ITextureRD_2D_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(TextureID);

    return r;
  }


  friend class ITextureBridge;
  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ITextureRD_2D>;  // Preserve2 元件須加上這個

};

// Render 單元要叫用 ITextureRD_2D 提供給其叫用的功能，須繼承此介面
class ITextureBridge
{
protected:
  // 由 Render 單元叫用，以取得 Mipmap 資料，若無法取得回覆 false
  bool cxxlFASTCALL GetMipmap(const unsigned char ***Mipmaps, const unsigned int **WidthHeight, unsigned int *LevelNum,
       const CxxlMan::Smart_Ptr<ITextureRD_2D> &ITextureRD_2D_Arg) const
  {
    return ITextureRD_2D_Arg->GetMipmap(Mipmaps, WidthHeight, LevelNum);
  }

  // 由 Render 單元叫用，以取得屬性資料
  void cxxlFASTCALL GetAttr(unsigned char &TextureAddrMode, unsigned int &TextureClampBorderRGBA, unsigned char &TextureMipmapMode, unsigned char &BlendMode, CxxlMan::CSmart_Ptr<const C3DMatrix4x4> &TextureMatrix_Arg,char &AutoTexCoordIndexMode,
       const CxxlMan::Smart_Ptr<ITextureRD_2D> &ITextureRD_2D_Arg) const
  {
    ITextureRD_2D_Arg->GetAttr(TextureAddrMode, TextureClampBorderRGBA, TextureMipmapMode, BlendMode, TextureMatrix_Arg, AutoTexCoordIndexMode);
  }

public:
  ITextureBridge(){}
  ~ITextureBridge(){}

};


}   /* namespace Cxxl3D */
#endif

